package com.jfinal.core;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jfinal.config.Constants;
import com.jfinal.config.JFinalConfig;
import com.jfinal.handler.Handler;
import com.jfinal.log.Logger;

/**
 * 改造 JFinalFilter 使之支持 spring
 * @ClassName: SpringJFinalFilter 
 * @author huangx
 * @date 2015年2月3日 上午10:58:15
 */
public class SpringJFinalFilter implements Filter {
	// jfinal classname param
	public static final String CONFIG_CLASSNAME_PARAM = "configClass";

	private Handler handler;
	private String encoding;
	private JFinalConfig jfinalConfig;
	private Constants constants;
	private static final JFinal jfinal = JFinal.me();
	private static Logger log;
	private int contextPathLength;
	
	// Adapter
	private static final JFinalAdapter jfinalAdapter = JFinalAdapter.on();

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// 初始化 ApplicationContext
		jfinalAdapter.initApplicationContext(filterConfig);
		
		createJFinalConfig(filterConfig.getInitParameter(CONFIG_CLASSNAME_PARAM));

		if (jfinalAdapter.init(jfinalConfig, filterConfig.getServletContext()) == false)
			throw new RuntimeException("JFinal init error!");
		
		handler = jfinal.getHandler();
		constants = Config.getConstants();
		encoding = constants.getEncoding();
		jfinalConfig.afterJFinalStart();

		String contextPath = filterConfig.getServletContext().getContextPath();
		contextPathLength = (contextPath == null || "/".equals(contextPath) ? 0 : contextPath.length());
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		request.setCharacterEncoding(encoding);

		String target = request.getRequestURI();
		if (contextPathLength != 0) target = target.substring(contextPathLength);

		boolean[] isHandled = { false };
		try {
			handler.handle(target, request, response, isHandled);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				String qs = request.getQueryString();
				log.error(qs == null ? target : target + "?" + qs, e);
			}
		}

		if (isHandled[0] == false) chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		jfinalConfig.beforeJFinalStop();
		jfinal.stopPlugins();
	}

	private void createJFinalConfig(String configClass) {
		if (configClass == null) throw new RuntimeException("Please set configClass parameter of JFinalFilter in web.xml");

		Object temp = null;
		try {
			temp = jfinalAdapter.registerJFinalBean(configClass);
		} catch (Exception e) {
			throw new RuntimeException("Can not create instance of class: " + configClass, e);
		}

		if (temp instanceof JFinalConfig) jfinalConfig = (JFinalConfig) temp;
		else throw new RuntimeException("Can not create instance of class: " + configClass
				+ ". Please check the config in web.xml");
	}

	static void initLogger() {
		log = Logger.getLogger(JFinalFilter.class);
	}
}
